iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0

今天來聊聊 Python一個很好用的 library -Pydantic,主要功能是做資料驗證和資料的解析,讓使用者可以在定義 data model 同時處理資料的驗證和轉換,減少多次來回可能的錯誤並確保 input & output 資料的一致性和有效性,近期在 Python 相關的許多專案總是離不開他的身影,就能知道它的好用。

Pydantic 優點

  • type hints

    • 透過定義型態來做資料驗證和序列化,每個 model 的屬性都會定義一個型態(如: int),Pydantic 會自動去驗證是否為 int。
  • 速度

    • Pydantic 的核心是用 Rust 編寫的。因此,Pydantic 是 Python 中最快的資料驗證 library 之一。
  • 解析 JSON 或其他資料格式

    • Pydantic 模型可以生成 JSON Schema 或從 JSON、字典或其他結構化資料格式中解析並建立資料模型。
  • Strict 和 Lax 模式

    • Pydantic 可以在 Strict(不會轉換資料型態)或 Lax 模式下運行,Pydantic 會嘗試將資料轉換為正確的型態。
  • 支援多種資料類型

    • Pydantic 支援許多 library 型態的驗證,包括 dataclass 和 TypedDict。
  • 客製化驗證

    • Pydantic 支援客製化 validators 和 serializers,可以很靈活的處理資料。

用法

from datetime import datetime

from pydantic import BaseModel, PositiveInt

//定義 data models 的資料型態
class User(BaseModel):
    id: int 
    name: str = 'Yusinz' // 也可以直接賦予 default 值
    birthday: datetime | None
    grade: dict[str, PositiveInt]


userdata = {
    'id': 123,
    'birthday': '2024-09-12 02:04',
    'grade': {
        'chinese': 9,
        'math': 7
    },
}

user = User(**userdata)

print(user.id)
print(user.model_dump()) // model_dump 為將 model -> json 快速提供給其他工具使用
"""
{
    'id': 123,
    'name': 'John Doe',
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1},
}
"""

因為是用 class 來定義,所以也能使用繼承 (inheritance)

from datetime import datetime

from pydantic import BaseModel, PositiveInt


class User(BaseModel):
    id: int
    name: str = 'Yusinz'
    birthday: datetime | None
    grade: dict[str, PositiveInt]

class Student(User):
    student_id: str

studentdata={
    'id': 1234,
    'name': 'Tom',
    'student_id': "13231",
    'birthday': '2024-09-12 02:04',
    'grade': {
        'chinese': 9,
        'math': 7
    },
}

student = User(**studentdata)
print(student.model_dump())
"""
{
    'id': 1234, 
    'name': 'Tom', 
    'birthday': datetime.datetime(2024, 9, 12, 2, 4), 
    'grade': {'chinese': 9, 'math': 7}, 
    'student_id': '13231'
}
"""

如果資料型態驗證錯誤就會報錯

pydantic_core._pydantic_core.ValidationError: 1 validation error for User
grade

如果該值可能為 None 也能使用 typing 的 Optional 讓該欄位可以為空。

class User(BaseModel):
    id: int
    name: str = 'Yusinz'
    birthday: datetime | None
    grade: Optional[dict[str, PositiveInt]]

也能透過 validator (v2 是 Field_validator) 來做資料客製化的驗證和轉換處理。

以下例子為

  • number 的邏輯轉換,乘以2
  • name 的長度客製化驗證
from pydantic import BaseModel, validator

class User(BaseModel):
    name: str
    number: int = 1

    @validator('number')
    @classmethod
    def double(cls, v: int) -> int:
        return v * 2

    @validator('name')
    @classmethod
    def name_must_longer_than_3(cls, v: str) -> str:
        if len(v) < 3:
            raise ValueError('name cannot be empty')
        return v

print(User(name='YY', number=10))
//pydantic.error_wrappers.ValidationError: 1 validation error for User
//name
  //name cannot be empty (type=value_error)

print(User(name='Yusinz', number=10)) // name='Yusinz' number=20

orm_mode

orm_mode = True 是 Pydantic 中的一個設定選項,它可以讓 Pydantic 模型與 ORM object(Object-Relational Mapping) 之間的轉換更為順暢。

orm_mode 的主要用途:

  1. 允許從 ORM object 中提取資料:當 orm_mode 設為 True 時,Pydantic 模型可以自動從 ORM object中提取數據,而不需要額外的轉換步驟。
  2. 使 Model 與 ORM 更兼容:在使用 ORM Library(如 SQLAlchemy)時,ORM object的屬性名稱和 Pydantic model 的欄位名稱可能不一致。啟用 orm_mode 可以幫助 Pydantic 模型識別 ORM 對象的屬性,並將其映射到模型中。

如何使用 orm_mode

假設有一個 SQLAlchemy ORM 的 object 和一個對應的 Pydantic model
就可以直接做驗證和解析,可以看到 dummy 因為在 pydantic 沒有使用,就被忽略掉了。

from pydantic import BaseModel

class User:
    id = 1
    name: str = "Yusinz"
    number: int = 1
    dummy = "dummy"

class UserModel(BaseModel):
    id: int
    name: str
    number: int

    class Config:
        orm_mode = True

user = UserModel.from_orm(User)
print(user.dict()) //{'id': 1, 'name': 'Yusinz', 'number': 1}

Reference


上一篇
Day-25 | Database - 刪除資料的差別 feat. TRUNCATE, DELETE, DROP
下一篇
Day-27 | Python - Functions & Closure
系列文
埋藏在後端工程下的地雷與寶藏30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言